package com.ding.easycontroller.service.impl;

import com.ding.easycontroller.dao.ControllerDao;
import com.ding.easycontroller.exception.CheckException;
import com.ding.easycontroller.service.ControllerService;
import com.ding.easycontroller.utils.AntUtils;
import com.ding.easycontroller.utils.IdStrategy;
import com.ding.easycontroller.work.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.ScriptEngine;
import java.util.ArrayList;
import java.util.List;

@Service
public class ControllerServiceImpl implements ControllerService {

    @Autowired
    private ControllerDao controllerDao;

    @Autowired
    private ScriptEngine scriptEngine;

    private List<Controller> controllers = new ArrayList<>();

    //对控制器进行排序
    private List<String> allowMethods = new ArrayList<>();

    {
        //任意请求方式
        allowMethods.add("*");
        allowMethods.add("GET");
        allowMethods.add("POST");
        allowMethods.add("PUT");
        allowMethods.add("DELETE");
    }


    private void preHandle(Controller controller) {

        //处理uri
        controller.setUri(controller.getUri().trim());

        //处理请求方法
        controller.setMethod(controller.getMethod().toUpperCase());

        //对路径进行变换
        String uri = controller.getUri();
        if (uri.contains("*")) {
            controller.setRegex(AntUtils.antPattern(uri));
        }

        //提取路径占位符
        String checkString = controller.getRegex() == null ? controller.getUri() : controller.getRegex();
        if (checkString.contains("{")) {
            List<String> vs = new ArrayList<>();
            String s = AntUtils.pathVariables(checkString, vs);
            controller.setRegexWithPathParams(s);
            controller.setPathParams(vs);
        }
        if (controller.getMethod().equals("*")) {
            controller.setRate(controller.getRate() + 1);
        }
    }

    private void check(Controller controller) {
        if (!controller.getUri().startsWith("/")) {
            throw new RuntimeException("请求地址必须以/开始");
        }

        if (controller.getUri().startsWith("/_config/")) {
            throw new RuntimeException("保留接口无法添加");
        }
        if (!allowMethods.contains(controller.getMethod())) {
            throw new RuntimeException("请求方式不允许:" + controller.getMethod());
        }

    }

    private void postHandle(Controller controller) {

        String method = controller.getMethod();

        String uri = controller.getUri();

        if (controller.getId() == null) {
            controller.setId(IdStrategy.createId(controller));
        }

        //判断当前是否已经具有该controller,如果有就禁止重复添加
        for (Controller c : controllers) {
            if (c.getUri().equals(controller.getUri()) && c.getMethod().equals(controller.getMethod())) {
                throw new RuntimeException("重复添加Controller:" + controller.getUri() + "_" + controller.getMethod());
            }
        }

        //计算模糊比例
        char[] chars = uri.toCharArray();
        int n = 0;
        for (char aChar : chars) {
            if (aChar == '*') {
                n++;
            }
        }
        double rate = n * 1.0 / uri.length();
        if (controller.getPathParams() != null) {
            rate += controller.getPathParams().size() * 0.5 / uri.length();
        }
        controller.setRate(rate);
    }

    private void initController(Controller controller) {

        controller.setScriptEngine(scriptEngine);

        try {
            controller.init();
        } catch (Exception e) {
            throw new CheckException(e);
        }
    }

    private void sortAndAdd(Controller controller) {
        double rate = controller.getRate();
        int i = 0;
        for (; i < controllers.size(); i++) {
            if (controllers.get(i).getRate() > rate) {
                break;
            }
        }
        controllers.add(i, controller);
    }

    private void tryAdd(Controller controller) {
        preHandle(controller);
        check(controller);
        postHandle(controller);
        initController(controller);
        sortAndAdd(controller);
    }

    @Override
    public Controller matchesController(String uri, String method) {

        for (Controller controller : controllers) {
            if (controller.getMethod().equals(method) || controller.getMethod().equals("*")) {
                if (controller.getRegexWithPathParams() != null) {
                    if (uri.matches(controller.getRegexWithPathParams())) {
                        return controller;
                    }
                } else if (controller.getRegex() != null) {
                    if (uri.matches(controller.getRegex())) {
                        return controller;
                    }
                } else {
                    if (uri.equals(controller.getUri())) {
                        return controller;
                    }
                }
            }
        }

        return null;
    }

    @Override
    public void removeById(String id) {
        Controller controller = getById(id);
        if (controller == null) {
            return;
        }
        controller.destroy();
        controllers.remove(controller);
        controllerDao.removeById(id);
    }

    @Override
    public void updateOrAdd(Controller controller) {

        if (controller.getId() != null) {
            Controller old = getById(controller.getId());
            if (old == null) {
                throw new RuntimeException("不存在的controller:" + controller.getId());
            }
            tryUpdate(controller, old);
            controllerDao.update(controller);
        } else {
            tryAdd(controller);
            controllerDao.add(controller);
        }

    }

    private void tryUpdate(Controller controller, Controller old) {

        old.destroy();
        controllers.remove(old);

        try {
            tryAdd(controller);
        } catch (Exception e) {
            old.init();
            controllers.add(old);
            throw e;
        }

    }


    @Override
    public Controller getById(String id) {
        for (Controller controller : controllers) {
            if (controller.getId().equals(id)) {
                return controller;
            }
        }
        return null;
    }

    @Override
    public List<Controller> listAll() {
        return controllers;
    }


    //恢复的过程中并没有进行排序运算,也没有处理
    @Override
    public void init() {

        //首先获取所有的controller
        List<Controller> all = controllerDao.listAll();
        for (Controller controller : all) {
            try {
                tryAdd(controller);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
